#include <iostream>
#include <vector>
#include <string>

#include <matrix>


class IntCell {
  public:
    explicit  IntCell( int initValue = 100)
      : mValue(initValue),
        value_p(nullptr) {
      value_p = new int;
    }

    IntCell(const IntCell& rhs)
      : mValue(rhs.mValue){
      // mValue = rhs.mValue;  
      std::cout << "IntCell copy constructor" << std::endl;
      value_p = new int(*rhs.value_p);
    }

    // = 号没有初始化列表了
    const IntCell& operator=(const IntCell& rhs){
      std::cout << "IntCell operator=" << std::endl;
      mValue = rhs.mValue; 
      value_p = new int(*rhs.value_p);
      return *this;
    }
    
    ~IntCell(){
      delete value_p;
    }

    int read() const {
      return mValue;
    }
    void write(int value) {
      mValue = value;
    }
  private:
    int mValue;
    int * value_p;
};

void count_array(int num){
  std::vector<int> array(num);

  for (int i = 0; i < array.size(); i++){
    array[i] = i * i;
    std::cout << "array[i]: " << array[i] << std::endl;

  }
}


// 函数模板

template <typename Comparable>
const Comparable & findMax (std::vector<Comparable> & a) {
  std::cout << "findMax 1" << std::endl;
  size_t max_idx = 0;
  for (size_t i = 0; i < a.size(); i++)
  {
    if (a[i] > a[max_idx]) {
      max_idx = i;
    }
  }
  return a[max_idx];  
}


//类模板

/**
 * 默认复制构造函数会利用成员mValue的类型Object,通过Object的复制构造函数初始化此对象的mValue,
 * 实现对象间值的深拷贝。

如果Object没有定义复制构造函数,编译时会报错。
所以通过Object的复制构造函数实现了成员变量mValue的深拷贝。这就是此类模板的默认复制构造函数的工作原理。
*/
template <typename Object>
class MemoryCell {
  public:
    explicit MemoryCell(const Object& init_value = Object())
      : mValue(init_value) {
      std::cout << "MemoryCell copy constructer " << std::endl;
      
    }
    MemoryCell(Object& init_value)
    {
      std::cout << "MemoryCell constructer " << std::endl;
      mValue = init_value;
    }

    const Object& operator=(const Object& _v){
      std::cout << "MemoryCell operator= " << std::endl;
      mValue = _v;\
      return *this;
    }

    const Object& read() {
      return mValue;
    }
    void write(const Object& v) {
      mValue = v;
    }

  private:
    Object mValue;
};


/////////////函数对象， 函数重载操作符///////////////////

template<typename Object, typename Comparator>
const Object& findMax(const std::vector<Object> vec, Comparator cmp){
  std::cout << "findMax 2" << std::endl;

  size_t max = 0;
  for (size_t i = 0; i < vec.size(); i++)
  {
    if (cmp(vec[max], vec[i])) {
      max = i;
    }
  }
  return vec[max];
}

class CaseInsensitiveCompare{
  public:
    bool operator()(const std::string & lhs, const std::string & rhs) {
      if (lhs < rhs) {
        return true;
      } else {
        return false;
      }
    }
};


int main(int argc, char** argv){
  std::cout << "hello world" << std::endl;

  IntCell cell;
  std::cout << "cell1: " << cell.read() << std::endl;
  
  IntCell cell2(88);
  std::cout << "cell2: " << cell2.read() << std::endl;

  // IntCell cell3;
  // cell3 = 55;
  count_array(5);
  IntCell* cell_p = new IntCell;

  cell_p->write(11);
  std::cout << "cell_p: " << cell_p->read() << std::endl;
  delete cell_p;

  std::string str1("Hello");
  std::string str2("hello world");
  if (str1 < str2) {
    std::cout << "str1 == str2 " << std::endl;
  } else {
    std::cout << "str1 != str2 " << std::endl;
  }

  IntCell cell_ori(50);

  IntCell cell_cp = cell_ori;
  IntCell cell_cp2;
  std::cout << "cell_cp: " << cell_cp.read() << std::endl;
  cell_cp2 = cell_ori;
  

  std::vector<int> array = {12, 4, 36, 5, 444, 101};
  std::cout << "array max: " << findMax(array) << std::endl;
  

  std::cout << "------------ class template ------------" << std::endl;
  MemoryCell<IntCell> cell3 = cell2;
  std::cout << "1" << std::endl;

  MemoryCell<std::string> cell4("hello");
  std::cout << "2" << std::endl;

  cell3.write(IntCell());
  std::cout << "3" << std::endl;

  std::cout << "cell4: " << cell4.read() << std::endl;


  std::vector<std::string> str_arr = {"aa", "ba", "ca"};

  std::string max = findMax(str_arr, CaseInsensitiveCompare());
  std::cout << "max str: " << max << std::endl;

  Matrix<int> point(3,3);
  std::cout << "Matrix<int> point numrows: " << point.numrows() << std::endl;

}